using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace Shrapnel.Interaction
{
	/// <summary>
	/// A helper class to wrap several events that together form 
	/// a single mouse action.
	/// </summary>
	public class LatentAction
	{
		public delegate void LatentActionHandler(Point mousePosition);

		public event LatentActionHandler Start;
		public event LatentActionHandler Tick;
		public event LatentActionHandler Stop;

		public void FireStart(MouseEventArgs args)
		{
			if (Start != null)
			{
				Start(args.Location);
			}
		}

		public void FireStop(MouseEventArgs args)
		{
			if (Stop != null)
			{
				Stop(args.Location);
			}
		}

		public void FireTick(MouseEventArgs args)
		{
			if (Tick != null)
			{
				Tick(args.Location);
			}
		}
	}

	public enum AboveElementType
	{
		None = 0,
		Node,
		Connector,
		Cable
	}


	/// <summary>
	/// The interaction manager processes incoming input (mouse events and keypress events) and
	/// maps those to the correct action events.
	/// </summary>
	public class Manager
	{
		/// <summary>
		/// The interaction mode of this workspace.
		/// </summary>
		private Mode mode = Mode.Normal;


		/// <summary>
		/// The interaction style to use, use the maya style by default.
		/// </summary>
		private Style style = new StyleMaya();


		/// <summary>
		/// The interaction style to use.
		/// </summary>
		public Style InteractionStyle 
		{
			get { return style; }
			set { style = value; }
		}


		/// <summary>
		/// The currently active interaction mode
		/// </summary>
		internal Mode InteractionMode
		{
			get { return mode; }
		}

		public delegate void InstantActionHandler();

		//
		// A list of all possible actions should be included here:
		//

		public LatentAction OnPanning = new LatentAction();
		public LatentAction OnZooming = new LatentAction();
		public LatentAction OnSelecting = new LatentAction();
		public LatentAction OnMoving = new LatentAction();
		public LatentAction OnWiring = new LatentAction();

		public InstantActionHandler OnFitSelectionInView = null;
		public InstantActionHandler OnFitAllInView = null;
		public InstantActionHandler OnDeleteSelection = null;
		public InstantActionHandler OnSelectAll = null;
		public InstantActionHandler OnDeselectAll = null;
		public InstantActionHandler OnCopySelection = null;
		public InstantActionHandler OnCutSelection = null;
		public InstantActionHandler OnPaste = null;
        public InstantActionHandler OnPrint = null;

		/// <summary>
		/// Process any mouse down event and decide which action
		/// to start (if any).
		/// </summary>
		/// <param name="e"></param>
		public void ProcessMouseDown(MouseEventArgs e, MouseButtons activeButtons, Keys modifierKeys, AboveElementType above)
		{
			// Only start a new mode, when in the normal mode! 
			if (mode == Mode.Normal)
			{
				if (style.ShouldStartPanning(activeButtons, modifierKeys, above))
				{
					OnPanning.FireStart(e);
					mode = Mode.Panning;
				}
				else if (style.ShouldStartZooming(activeButtons, modifierKeys, above))
				{
					OnZooming.FireStart(e);
					mode = Mode.Zooming;
				}
				else if (style.ShouldStartSelecting(activeButtons, modifierKeys, above))
				{
					OnSelecting.FireStart(e);
					mode = Mode.Selecting;
				}
				else if (style.ShouldStartMoving(activeButtons, modifierKeys, above))
				{
					OnMoving.FireStart(e);
					mode = Mode.Moving;
				}
				else if (style.ShouldStartWiring(activeButtons, modifierKeys, above))
				{
					OnWiring.FireStart(e);
					mode = Mode.Wiring;
				}
			}
		}

		/// <summary>
		/// Process any mouse up event and decide if we have to stop the currently active
		/// action.
		/// </summary>
		/// <param name="e"></param>
		public void ProcessMouseUp(MouseEventArgs e, MouseButtons activeButtons, Keys modifierKeys)
		{
			switch (mode)
			{
				case Mode.Panning:
					if (style.ShouldStopPanning(e.Button, modifierKeys))
					{
						OnPanning.FireStop(e);
						mode = Mode.Normal;
					}					
					break;
				case Mode.Selecting:
					if (style.ShouldStopSelecting(activeButtons, modifierKeys))
					{
						OnSelecting.FireStop(e);
						mode = Mode.Normal;
					}					
					break;
				case Mode.Zooming:
					if (style.ShouldStopZooming(activeButtons, modifierKeys))
					{
						OnZooming.FireStop(e);
						mode = Mode.Normal;
					}					
					break;
				case Mode.Moving:
					if (style.ShouldStopMoving(activeButtons, modifierKeys))
					{
						OnMoving.FireStop(e);
						mode = Mode.Normal;
					}
					break;
				case Mode.Wiring:
					if (style.ShouldStopWiring(activeButtons, modifierKeys))
					{
						OnWiring.FireStop(e);
						mode = Mode.Normal;
					}
					break;
			}
		}


		/// <summary>
		/// Process any mouse move event and decide if we should keep our currently active action
		/// active.
		/// </summary>
		/// <param name="e"></param>
		public void ProcessMouseMove(MouseEventArgs e, MouseButtons activeButtons, Keys modifierKeys)
		{
			switch (mode)
			{
				case Mode.Panning:
					if (style.ShouldStopPanning(activeButtons, modifierKeys))
					{
						OnPanning.FireStop(e);
						mode = Mode.Normal;
					} else 
					{
						OnPanning.FireTick(e);
					}
					break;
				case Mode.Selecting:
					if (style.ShouldStopSelecting(activeButtons, modifierKeys))
					{
						OnSelecting.FireStop(e);
						mode = Mode.Normal;
					}
					else
					{
						OnSelecting.FireTick(e);
					}
					break;
				case Mode.Zooming:
					if (style.ShouldStopZooming(activeButtons, modifierKeys))
					{
						OnZooming.FireStop(e);
						mode = Mode.Normal;
					}
					else
					{
						OnZooming.FireTick(e);
					}
					break;
				case Mode.Moving:
					if (style.ShouldStopMoving(activeButtons, modifierKeys))
					{
						OnMoving.FireStop(e);
						mode = Mode.Normal;
					}
					else
					{
						OnMoving.FireTick(e);
					}
					break;
				case Mode.Wiring:
					if (style.ShouldStopWiring(activeButtons, modifierKeys))
					{
						OnWiring.FireStop(e);
						mode = Mode.Normal;
					}
					else
					{
						OnWiring.FireTick(e);
					}
					break;
			}
		}


		/// <summary>
		/// Process a key event and fire the mapped action
		/// </summary>
		/// <param name="e"></param>
		/// <param name="modifierKeys"></param>
		public void ProcessKeyDown(KeyEventArgs e, Keys modifierKeys)
		{
			// Only process keys when not doing anything special!
			if (mode != Mode.Normal)
				return;


			if (style.ShouldDoFitSelectionInView(e, modifierKeys) && (OnFitSelectionInView != null))
			{
				OnFitSelectionInView();
			}
			else if (style.ShouldDoFitAllInView(e, modifierKeys) && (OnFitAllInView != null))
			{
				OnFitAllInView();
			}
			else if (style.ShouldDoDeleteSelection(e, modifierKeys) && (OnDeleteSelection != null))
			{
				OnDeleteSelection();
			}
			else if (style.ShouldDoSelectAll(e, modifierKeys) && (OnSelectAll != null))
			{
				OnSelectAll();
			}
			else if (style.ShouldDoDeselectAll(e, modifierKeys) && (OnDeselectAll != null))
			{
				OnDeselectAll();
			}
			else if (style.ShouldDoCopySelection(e, modifierKeys) && (OnCopySelection != null))
			{
				OnCopySelection();
			}
			else if (style.ShouldDoCutSelection(e, modifierKeys) && (OnCutSelection != null))
			{
				OnCutSelection();
            }
            else if (style.ShouldDoPaste(e, modifierKeys) && (OnPaste != null))
            {
                OnPaste();
            }
            else if (style.ShouldPrint(e, modifierKeys) && (OnPrint != null))
            {
                OnPrint();
            }
		}

		/// <summary>
		/// Reset the interaction manager. This ungracefully resets
		/// this manager.
		/// </summary>
		public void Reset()
		{
			mode = Mode.Normal;
		}

	}
}
